package com.wmjsoft.validator.utils

import java.beans.PropertyDescriptor
import java.lang.Exception
import java.lang.reflect.Field
import java.math.BigInteger
import java.util.*
import java.util.function.Consumer
import kotlin.collections.HashMap

object ClassUtil {
    /**
     * description: 该方法用于传入某实例对象以及对象方法名、修改值，通过放射调用该对象的某个set方法设置修改值
     *
     * @param beanObj  beanObj
     * @param property property
     * @param value    value
     * @return [Object]
     */
    fun <T> setProperty(beanObj: T?, property: String?, value: Any?): Any? {
        return try {
            if (beanObj == null) {
                throw RuntimeException("beanObj为空")
            } else if (property == null || property == "") {
                throw RuntimeException("property为空")
            } else {
                val pd = PropertyDescriptor(property, beanObj.javaClass)
                val setMethod = pd.writeMethod ?: throw RuntimeException(beanObj.javaClass.name + "没有实体" + property)
                setMethod.invoke(beanObj, value)
            }
        } catch (e: Exception) {
            throw java.lang.RuntimeException(e.message)
        }
    }

    /**
     * description: 该方法用于传入某实例对象以及对象方法名、修改值，通过放射调用该对象的某个set方法设置修改值
     *
     * @param beanObj  beanObj
     * @param property property
     * @param value    value
     * @param clazz    clazz
     * @return [Object]
     */
    fun <T> setProperty(beanObj: T?, property: String?, value: Any, clazz: Class<*>): Any? {
        var value = value
        return try {
            if (beanObj == null) {
                throw RuntimeException("beanObj为空")
            } else if (property == null || property == "") {
                throw RuntimeException("property为空")
            } else {
                val pd = PropertyDescriptor(property, beanObj.javaClass)
                val setMethod = pd.writeMethod ?: throw RuntimeException(beanObj.javaClass.name + "没有实体" + property)
                if (clazz.name.contains("Long")) {
                    value = value.toString().toLong()
                } else if (clazz.name.contains("BigInteger")) {
                    value = BigInteger.valueOf((value as Long))
                }
                setMethod.invoke(beanObj, value)
            }
        } catch (e: Exception) {
            throw RuntimeException(e.message)
        }
    }

    /**
     * description: 该方法用于传入某实例对象以及对象方法名，通过反射调用该对象的某个get方法
     *
     * @param beanObj  beanObj
     * @param property property
     * @return [Object]
     */
    fun <T> getProperty(beanObj: T?, property: String?): Any {
        return try {
            if (beanObj == null) {
                throw RuntimeException("beanObj为空")
            } else if (property == null || property == "") {
                throw RuntimeException("property为空")
            } else {
                val pd = PropertyDescriptor(property, beanObj.javaClass)
                val getMethod = pd.readMethod ?: throw RuntimeException(beanObj.javaClass.name + "没有实体" + property)
                getMethod.invoke(beanObj)
            }
        } catch (e: Exception) {
            throw RuntimeException(e.message)
        }
    }

    /**
     * description: 判断列是否存在
     *
     * @param beanObj  beanObj
     * @param property property
     * @return [boolean]
     */
    fun <T> hasColumn(beanObj: T, property: String?): Boolean {
        try {
            val pd = PropertyDescriptor(property, beanObj!!::class.java)
            val getMethod = pd.readMethod ?: return false
        } catch (e: Exception) {
            return false
        }
        return true
    }

    /**
     * description: 将对象中不为null的字断转换为map
     *
     * @param t t
     * @return [,][<]
     */
    fun tToMap(t: Any): Map<String, Any>? {
        val map: MutableMap<String, Any> = HashMap()
        val childFields = t.javaClass.declaredFields
        val superTClassFields = t.javaClass.superclass.declaredFields
        val fields = getFieldsName(childFields, superTClassFields)
        for (filed in fields) {
            val value: Any = getProperty<Any>(t, filed)
            if (value != null) {
                map[filed] = value
            }
        }
        return map
    }

    /**
     * description:
     *
     * @param fields fields
     * @return [ ][<]
     */
    fun getFieldsName(vararg fields: Array<Field>): List<String> {
        val fieldsName: MutableList<String> = ArrayList()
        if (fields.isEmpty()) {
            return fieldsName
        }
        val fields = listOf<Array<Field>>(*fields)
        fields.forEach(Consumer { fs: Array<Field> ->
            listOf(*fs).forEach(
                Consumer { f: Field -> fieldsName.add(f.name) })
        })
        return fieldsName
    }

}